package com.g8.pethospitallearnbackend.service.impls;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.g8.pethospitallearnbackend.entity.*;
import com.g8.pethospitallearnbackend.exception.CustomException;
import com.g8.pethospitallearnbackend.mapper.UserMapper;
import com.g8.pethospitallearnbackend.service.EmailService;
import com.g8.pethospitallearnbackend.service.UserService;
import com.g8.pethospitallearnbackend.utils.NewIdGenerateUtil;
import com.g8.pethospitallearnbackend.utils.RedisUtil;
import com.g8.pethospitallearnbackend.utils.ValidateUtil;
import com.g8.pethospitallearnbackend.utils.responseUtil.ResponseStatusEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {

    @Value("{rsa.private-key}")
    private String privateKey;
    @Autowired
    private UserMapper userMapper;
    // 邮箱验证码过期时间
    @Value("${code.expiration}")
    private Long expiration;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private final EmailService emailService;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Override
    public User getUserById(String userId) {
        return userMapper.selectByPrimaryKey(userId);
    }

    @Override
    public User login(String userNameOrEmail, String password) {
        UserExample userExample = new UserExample();
        if (userNameOrEmail.contains("@"))
            userExample.createCriteria().andUserEmailEqualTo(userNameOrEmail);
        else
            userExample.createCriteria().andUserNameEqualTo(userNameOrEmail);
        List<User> users = userMapper.selectByExample(userExample);
        if (users.size() != 1) {
            throw new CustomException(ResponseStatusEnum.DATA_NOT_EXIST, "用户不存在！");
        } else if (null == users.get(0))
            throw new CustomException(ResponseStatusEnum.DATA_NOT_EXIST, "用户不存在！");
        else {
            User user = users.get(0);
            if (passwordEncoder.matches(password, user.getUserPassword())) return user;
            else throw new CustomException(ResponseStatusEnum.SYSTEM_ERROR, "用户密码错误！");
        }
    }

    @Override
    public User register(User user) {
        // 先进行一波格式校验
        if (!ValidateUtil.isUsername(user.getUserName()))
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "用户名格式错误");
        if (!ValidateUtil.isEmail(user.getUserEmail())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "邮箱格式错误");
        }
        if (!ValidateUtil.isMobile(user.getUserPhone())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "手机号格式错误");
        }
        if (!ValidateUtil.isPassword(user.getUserPassword())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "密码格式错误");
        }
        if (!user.getUserBirth().isEmpty() && !user.getUserBirth().isBlank()) {
            if(!ValidateUtil.isDate(user.getUserBirth())) throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "出生日期格式错误");
        }

        // 验证邮箱验证码
        // 用email获取redis中的code
        Object codeValue = redisUtil.get(user.getUserEmail());
        if (codeValue == null || !codeValue.toString().equals(user.getEmailCode())) {
            throw new CustomException(ResponseStatusEnum.SYSTEM_ERROR, "邮箱验证码错误！");
        } else
            redisUtil.del(user.getUserEmail());

        // 随机生成id
        String id = NewIdGenerateUtil.getNumber(8);
        User repeat = this.getUserById(id);
        while(repeat != null) {
            id = NewIdGenerateUtil.getNumber(8);
            repeat = this.getUserById(id);
        }
        user.setUserId(id);
        // 设置实习生身份
        user.setUserRole((byte) 1);
        // 密码加密
        try {
//            user.setUserPassword(passwordEncoder.encode(RSAUtil.decryptByPrivateKey(privateKey, user.getUserPassword())));
            user.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
        } catch (Exception e) {
            throw new RuntimeException("注册密码异常");
        }
        userMapper.insert(user);
        return this.getUserById(id);
    }

    @Override
    public String verifyEMail(String email) {
        // 查看注册邮箱是否已经存在
        UserExample userExample = new UserExample();
        userExample.createCriteria().andUserEmailEqualTo(email);
        if (!userMapper.selectByExample(userExample).isEmpty()) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "注册邮箱已存在");
        }
        return sendMailCode(email);
    }


    @Override
    public String sendMailCode(String email) {
        // 先校验一下邮箱格式
        if (!ValidateUtil.isEmail(email)) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "邮箱格式错误");
        }
        // 获取发送邮箱验证码的HTML模板
        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("templates", TemplateConfig.ResourceMode.CLASSPATH));
        Template template = engine.getTemplate("email-code.ftl");

        // 从redis缓存中尝试获取验证码
        Object code = redisUtil.get(email);
        if (code == null) {
            // 如果在缓存中未获取到验证码，则产生6位随机数，放入缓存中
            code = RandomUtil.randomNumbers(6);
            if (!redisUtil.set(email, code, expiration)) {
                throw new RuntimeException("后台缓存服务异常");
            }
        }
        // 发送验证码
//        emailService.sendSimpleEmail(new EmailSend(email,
//                "邮箱验证码", template.render(Dict.create().set("code", code))));
        emailService.sendComplexEmail(new EmailSend(email,
                "邮箱验证码", template.render(Dict.create().set("code", code))));
        return code.toString();
    }

    @Override
    public User modifyEmail(User user) {
        // 先进行一波格式校验
        if (!ValidateUtil.isEmail(user.getUserEmail())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "邮箱格式错误");
        }
        if (user.getEmailCode().isBlank()) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "请输入邮箱验证码！");
        }
        // 检验一下邮箱是否已注册了，避免重复邮箱
        UserExample userExample = new UserExample();
        userExample.createCriteria().andUserEmailEqualTo(user.getUserEmail());
        if(!userMapper.selectByExample(userExample).isEmpty()) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "该邮箱已经注册了！");
        }
        User user1 = userMapper.selectByPrimaryKey(user.getUserId());
        if (user1 == null) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "用户不存在！");
        }
        // 验证邮箱验证码
        // 用email获取redis中的code
        Object codeValue = redisUtil.get(user.getUserEmail());
        if (codeValue == null || !codeValue.toString().equals(user.getEmailCode())) {
            throw new CustomException(ResponseStatusEnum.SYSTEM_ERROR, "邮箱验证码错误！");
        } else
            redisUtil.del(user.getUserEmail());
        // 验证通过，更新
        user1.setUserEmail(user.getUserEmail());
        userMapper.updateByPrimaryKey(user1);
        return userMapper.selectByPrimaryKey(user.getUserId());
    }

    @Override
    public User modifyPassword(PasswordModify passwordModify) {
        if (passwordModify.getUserId().isBlank() || passwordModify.getOldPassword().isBlank()
                || passwordModify.getNewPassword().isBlank())
            throw new CustomException(ResponseStatusEnum.MISS_PARAM);
        User user = userMapper.selectByPrimaryKey(passwordModify.getUserId());
        if(user == null) throw new CustomException(ResponseStatusEnum.DATA_NOT_EXIST);
        if (!passwordEncoder.matches(passwordModify.getOldPassword(), user.getUserPassword()))
            throw new CustomException(ResponseStatusEnum.SYSTEM_ERROR, "旧密码不正确！");
        if (!ValidateUtil.isPassword(passwordModify.getNewPassword())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "新密码不合法！");
        }
        user.setUserPassword(passwordEncoder.encode(passwordModify.getNewPassword()));
        userMapper.updateByPrimaryKey(user);
        return userMapper.selectByPrimaryKey(passwordModify.getUserId());
    }

    @Override
    public User resetPassword(PasswordReset passwordReset) {
        if (!ValidateUtil.isEmail(passwordReset.getEmail())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "邮箱格式错误");
        }
        if (passwordReset.getEmailCode().isBlank()) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "请输入邮箱验证码！");
        }
        if (!ValidateUtil.isPassword(passwordReset.getNewPassword())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "密码格式错误");
        }
        // 检验一下邮箱是否已注册了，避免重复邮箱
        UserExample userExample = new UserExample();
        userExample.createCriteria().andUserEmailEqualTo(passwordReset.getEmail());
        List<User> users = userMapper.selectByExample(userExample);
        if(users.isEmpty()) {
            throw new CustomException(ResponseStatusEnum.DATA_NOT_EXIST, "该邮箱并未注册过！");
        } else if (users.size() > 1) {
            throw new CustomException(ResponseStatusEnum.SYSTEM_ERROR, "有重复邮箱！");
        }
        User user = users.get(0);
        // 验证邮箱验证码
        // 用email获取redis中的code
        Object codeValue = redisUtil.get(passwordReset.getEmail());
        if (codeValue == null || !codeValue.toString().equals(passwordReset.getEmailCode())) {
            throw new CustomException(ResponseStatusEnum.SYSTEM_ERROR, "邮箱验证码错误！");
        } else
            redisUtil.del(passwordReset.getEmail());
        // 验证通过，更新
        user.setUserPassword(passwordEncoder.encode(passwordReset.getNewPassword()));
        userMapper.updateByPrimaryKey(user);
        return userMapper.selectByPrimaryKey(user.getUserId());

    }

    /**
     * 只更新用户名、手机号、性别、出生日期
     * @param user
     * @return
     */
    @Override
    public User modifyInfo(User user) {
        // 先进行一波格式校验
        if (!ValidateUtil.isUsername(user.getUserName()))
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "用户名格式错误");
        if (!ValidateUtil.isMobile(user.getUserPhone())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "手机号格式错误");
        }
        if(!ValidateUtil.isDate(user.getUserBirth())) throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "出生日期格式错误");
        if(!ValidateUtil.isGender(user.getUserGender())) throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "性别格式错误，gender只能是0/1");
        User userDB = userMapper.selectByPrimaryKey(user.getUserId());
        if (userDB == null) throw new CustomException(ResponseStatusEnum.DATA_NOT_EXIST, "要修改的用户不存在");
        userDB.setUserName(user.getUserName());
        userDB.setUserPhone(user.getUserPhone());
        userDB.setUserBirth(user.getUserBirth());
        userDB.setUserGender(user.getUserGender());
        userMapper.updateByPrimaryKey(userDB);
        return userMapper.selectByPrimaryKey(user.getUserId());
    }

    @Override
    public User modifyAUser(User user) {
        // 先进行一波格式校验
        if (!ValidateUtil.isUsername(user.getUserName()))
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "用户名格式错误");
        if (!ValidateUtil.isEmail(user.getUserEmail())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "邮箱格式错误");
        }
        if (!ValidateUtil.isMobile(user.getUserPhone())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "手机号格式错误");
        }
        if (!user.getUserPassword().isEmpty() && !user.getUserPassword().isBlank()) {
            if (!ValidateUtil.isPassword(user.getUserPassword()))
                throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "密码格式错误");
        }

        if (!user.getUserBirth().isEmpty() && !user.getUserBirth().isBlank()) {
            if(!ValidateUtil.isDate(user.getUserBirth())) throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "出生日期格式错误");
        }
        User userDB = userMapper.selectByPrimaryKey(user.getUserId());
        if (userDB == null)
            throw new CustomException(ResponseStatusEnum.DATA_NOT_EXIST, "要修改的用户不存在");

        userDB.setUserEmail(user.getUserEmail());
        // 密码加密，这里要注意如果用户不修改密码的话传送的就是空白
        if (!user.getUserBirth().isEmpty() && !user.getUserPassword().isBlank())
            userDB.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
        userDB.setUserName(user.getUserName());
        userDB.setUserGender(user.getUserGender());
        userDB.setUserBirth(user.getUserBirth());
        userDB.setUserPhone(user.getUserPhone());

        userMapper.updateByPrimaryKey(userDB);
        return userMapper.selectByPrimaryKey(user.getUserId());
    }

    @Override
    public User addAUser(User user) {
        // 先进行一波格式校验
        if (!ValidateUtil.isUsername(user.getUserName()))
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "用户名格式错误");
        if (!ValidateUtil.isEmail(user.getUserEmail())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "邮箱格式错误");
        }
        if (!ValidateUtil.isMobile(user.getUserPhone())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "手机号格式错误");
        }
        if (!ValidateUtil.isPassword(user.getUserPassword())) {
            throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "密码格式错误");
        }
        if (!user.getUserBirth().isEmpty() && !user.getUserBirth().isBlank()) {
            if(!ValidateUtil.isDate(user.getUserBirth())) throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "出生日期格式错误");
        }
        // 校验role
        if (user.getUserRole() != 0 && user.getUserRole() != 1) throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "用户身份role只能是0/1");

        // 随机生成id
        String id = NewIdGenerateUtil.getNumber(8);
        User repeat = this.getUserById(id);
        while(repeat != null) {
            id = NewIdGenerateUtil.getNumber(8);
            repeat = this.getUserById(id);
        }
        user.setUserId(id);
        // 密码加密
        try {
//            user.setUserPassword(passwordEncoder.encode(RSAUtil.decryptByPrivateKey(privateKey, user.getUserPassword())));
            user.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
        } catch (Exception e) {
            throw new RuntimeException("注册密码异常");
        }
        userMapper.insert(user);
        return this.getUserById(id);
    }

    @Override
    public User modifyPermission(User user) {
        if (user.getUserRole() == null || user.getUserId() == null) throw new CustomException(ResponseStatusEnum.MISS_PARAM);
        // 校验role
        if (user.getUserRole() != 0 && user.getUserRole() != 1) throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "用户身份role只能是0/1");

        User userDB = userMapper.selectByPrimaryKey(user.getUserId());
        userDB.setUserRole(user.getUserRole());
        userMapper.updateByPrimaryKey(userDB);
        return userMapper.selectByPrimaryKey(user.getUserId());
    }

    @Override
    public boolean isAdmin(String userId) {
        User user = userMapper.selectByPrimaryKey(userId);
        return user.getUserRole() == 0;
    }

    @Override
    public List<User> getUserOfARole(Byte role) {
        if (role == 0) {
            UserExample userExample = new UserExample();
            userExample.createCriteria().andUserRoleEqualTo(role);
            return userMapper.selectByExample(userExample);
        } else if (role == 1) {
            UserExample userExample = new UserExample();
            userExample.createCriteria().andUserRoleEqualTo(role);
            return userMapper.selectByExample(userExample);
        }
        return userMapper.selectList(null);
    }

    @Override
    public String deleteAUser(String userId) {
        if (userMapper.deleteByPrimaryKey(userId) < 1) throw new CustomException(ResponseStatusEnum.DATA_NOT_EXIST, "未查询到待删除用户");
        if (userMapper.selectByPrimaryKey(userId) == null) return "用户已成功删除";
        throw new CustomException(ResponseStatusEnum.SYSTEM_ERROR);
    }

    @Override
    public String deleteUserInBulk(StringList userIds) {
        StringBuffer msg = new StringBuffer();
        int re = 0;
        for (String userId : userIds.getList()) {
            int result = userMapper.deleteByPrimaryKey(userId);
            if (result < 1) msg.append("未查询到待删除用户").append(userId).append("\n");
            else re += result;
        }
        msg.append("共成功删除").append(re).append("个用户");
        return msg.toString();
    }

    @Override
    public String modifyPermissionsInBulk(PermissionModifyInBulk perModiInBulk) {
        // 校验role
        if (perModiInBulk.getUserRole() != 0 && perModiInBulk.getUserRole() != 1) throw new CustomException(ResponseStatusEnum.BAD_REQUEST, "用户身份role只能是0/1");
        StringBuffer reMsg = new StringBuffer();
        for(String userId : perModiInBulk.getUserIds()) {
            User user = userMapper.selectByPrimaryKey(userId);
            if (user == null) reMsg.append("用户").append(userId).append("不存在\n");
            else {
                user.setUserRole(perModiInBulk.getUserRole());
                if (userMapper.updateByPrimaryKey(user) == 1)
                    reMsg.append("用户").append(userId).append("的权限修改成功\n");
            }
        }
        return reMsg.toString();
    }


}
